/*     */ package com.zimbra.soap;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.HeaderConstants;
/*     */ import com.zimbra.common.soap.MailConstants;
/*     */ import com.zimbra.common.soap.SoapFaultException;
/*     */ import com.zimbra.common.soap.SoapParseException;
/*     */ import com.zimbra.common.soap.SoapProtocol;
/*     */ import com.zimbra.common.soap.SoapTransport;
/*     */ import com.zimbra.common.soap.XmlParseException;
/*     */ import com.zimbra.common.soap.ZimbraNamespace;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.AccessManager;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AccountServiceException;
/*     */ import com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.redolog.RedoLogProvider;
/*     */ import com.zimbra.cs.service.AuthProvider;
/*     */ import com.zimbra.cs.service.admin.AdminAccessControl;
/*     */ import com.zimbra.cs.service.admin.AdminDocumentHandler;
/*     */ import com.zimbra.cs.servlet.CsrfTokenException;
/*     */ import com.zimbra.cs.servlet.util.CsrfUtil;
/*     */ import com.zimbra.cs.session.Session;
/*     */ import com.zimbra.cs.session.SessionCache;
/*     */ import com.zimbra.cs.session.SoapSession;
/*     */ import com.zimbra.cs.stats.ActivityTracker;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import com.zimbra.cs.util.AccountUtil;
/*     */ import com.zimbra.cs.util.BuildInfo;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import java.io.ByteArrayInputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.util.Map;
/*     */ import javax.servlet.ServletRequest;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.xml.stream.XMLInputFactory;
/*     */ import javax.xml.stream.XMLStreamException;
/*     */ import javax.xml.stream.XMLStreamReader;
/*     */ import org.dom4j.Namespace;
/*     */ import org.dom4j.QName;
/*     */ import org.eclipse.jetty.continuation.Continuation;
/*     */ import org.eclipse.jetty.continuation.ContinuationSupport;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class SoapEngine
/*     */ {
/*  79 */   private static final Log LOG = LogFactory.getLog(SoapEngine.class);
/*     */   
/*     */ 
/*     */   public static final String A_REQUEST_CORRELATOR = "requestId";
/*     */   
/*     */ 
/*     */   public static final String ZIMBRA_CONTEXT = "zimbra.context";
/*     */   
/*     */ 
/*     */   public static final String ZIMBRA_ENGINE = "zimbra.engine";
/*     */   
/*     */ 
/*     */   public static final String ZIMBRA_SESSION = "zimbra.session";
/*     */   
/*     */ 
/*     */   public static final String REQUEST_IP = "request.ip";
/*     */   
/*     */ 
/*     */   public static final String SOAP_REQUEST_IP = "soap.request.ip";
/*     */   
/*     */ 
/*     */   public static final String SOAP_REQUEST_LOGGED = "soap.request.logged";
/*     */   
/*     */ 
/*     */   public static final String ORIG_REQUEST_IP = "orig.request.ip";
/*     */   
/*     */ 
/* 106 */   private final DocumentDispatcher dispatcher = new DocumentDispatcher();
/*     */   
/*     */   SoapEngine() {
/* 109 */     SoapTransport.setDefaultUserAgent("ZCS", BuildInfo.VERSION);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private Element soapFaultEnv(SoapProtocol soapProto, String msg, ServiceException e)
/*     */   {
/* 117 */     logFault(msg, e);
/* 118 */     return soapProto.soapEnvelope(soapProto.soapFault(e));
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private Element soapFault(SoapProtocol soapProto, String msg, ServiceException e)
/*     */   {
/* 125 */     logFault(msg, e);
/* 126 */     return soapProto.soapFault(e);
/*     */   }
/*     */   
/*     */   private void logFault(String msg, ServiceException e) {
/* 130 */     if ((e.getCode().equals("service.AUTH_EXPIRED")) || (e.getCode().equals("service.AUTH_REQUIRED"))) {
/* 131 */       StackTraceElement[] s = Thread.currentThread().getStackTrace();
/* 132 */       StackTraceElement callSite = s[4];
/* 133 */       e.setIdLabel(callSite);
/* 134 */       LOG.warn("%s%s", new Object[] { e.getMessage(), ": " + msg });
/* 135 */       LOG.debug(msg, e);
/*     */     } else {
/* 137 */       LOG.warn(msg, e);
/*     */     }
/*     */   }
/*     */   
/* 141 */   private void logRequest(Map<String, Object> context, Element envelope) { if ((ZimbraLog.soap.isTraceEnabled()) && (!context.containsKey("soap.request.logged"))) {
/* 142 */       HttpServletRequest servletRequest = (HttpServletRequest)context.get("servlet.request");
/* 143 */       boolean isResumed = !ContinuationSupport.getContinuation(servletRequest).isInitial();
/* 144 */       ZimbraLog.soap.trace(!isResumed ? "C:\n%s" : "C: (resumed)\n%s", new Object[] { envelope.prettyPrint(true) });
/* 145 */       context.put("soap.request.logged", Boolean.TRUE);
/*     */     }
/*     */   }
/*     */   
/*     */   private void logUnparsableRequest(Map<String, Object> context, byte[] soapMessage, String parseError) {
/* 150 */     if (context.containsKey("soap.request.logged")) {
/* 151 */       return;
/*     */     }
/* 153 */     if (ZimbraLog.soap.isInfoEnabled()) {
/* 154 */       HttpServletRequest servletRequest = (HttpServletRequest)context.get("servlet.request");
/* 155 */       boolean isResumed = !ContinuationSupport.getContinuation(servletRequest).isInitial();
/* 156 */       if (ZimbraLog.soap.isTraceEnabled()) {
/* 157 */         ZimbraLog.soap.trace(!isResumed ? "C: (ParseError:%s)\n%s" : "C: (resumed) (ParseError:%s)\n%s", new Object[] { parseError, new String(soapMessage) });
/*     */       }
/* 159 */       else if (soapMessage.length < 2000) {
/* 160 */         ZimbraLog.soap.info(!isResumed ? "C: (ParseError:%s)\n%s" : "C: (resumed) (ParseError:%s)\n%s", new Object[] { parseError, new String(soapMessage) });
/*     */       }
/*     */       
/* 163 */       context.put("soap.request.logged", Boolean.TRUE);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private SoapProtocol chooseFaultProtocolFromBadXml(InputStream in)
/*     */   {
/* 173 */     SoapProtocol soapProto = SoapProtocol.Soap12;
/* 174 */     XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
/* 175 */     XMLStreamReader xmlReader = null;
/* 176 */     int depth = 0;
/* 177 */     boolean inEnvelope = false;
/* 178 */     boolean inHeader = false;
/* 179 */     boolean inContext = false;
/*     */     try
/*     */     {
/* 182 */       xmlReader = xmlInputFactory.createXMLStreamReader(in);
/* 183 */       boolean scanningForFormat = true;
/* 184 */       while ((scanningForFormat) && (xmlReader.hasNext())) {
/* 185 */         int eventType = xmlReader.next();
/* 186 */         String localName; switch (eventType) {
/*     */         case 1: 
/* 188 */           localName = xmlReader.getLocalName();
/* 189 */           depth++;
/* 190 */           if ((depth == 1) && ("Envelope".equals(localName))) {
/* 191 */             inEnvelope = true;
/* 192 */             String ns = xmlReader.getNamespaceURI();
/* 193 */             if (SoapProtocol.Soap11.getNamespace().getStringValue().equals(ns)) {
/* 194 */               soapProto = SoapProtocol.Soap11;
/*     */             }
/* 196 */           } else if ((inEnvelope) && (depth == 2) && ("Header".equals(localName))) {
/* 197 */             inHeader = true;
/* 198 */           } else if ((inHeader) && (depth == 3) && ("context".equals(localName))) {
/* 199 */             inContext = true;
/* 200 */           } else if ((inContext) && (depth == 4) && ("format".equals(localName))) {
/* 201 */             String respType = xmlReader.getAttributeValue(null, "type");
/* 202 */             if (respType != null) {
/* 203 */               if ("js".equals(respType)) {
/* 204 */                 soapProto = SoapProtocol.SoapJS;
/*     */               }
/* 206 */               scanningForFormat = false;
/*     */             } }
/* 208 */           break;
/*     */         
/*     */         case 2: 
/* 211 */           localName = xmlReader.getLocalName();
/* 212 */           if ((depth == 1) && ("Envelope".equals(localName))) {
/* 213 */             inEnvelope = false;
/* 214 */             scanningForFormat = false;
/* 215 */           } else if ((inEnvelope) && (depth == 2) && ("Header".equals(localName))) {
/* 216 */             inHeader = false;
/* 217 */             scanningForFormat = false;
/* 218 */           } else if ((inHeader) && (depth == 3) && ("context".equals(localName))) {
/* 219 */             inContext = false;
/* 220 */             scanningForFormat = false;
/*     */           }
/* 222 */           depth--;
/*     */         }
/*     */         
/*     */       }
/*     */       
/*     */ 
/*     */ 
/* 229 */       if (xmlReader != null) {
/*     */         try {
/* 231 */           xmlReader.close();
/*     */         }
/*     */         catch (XMLStreamException e) {}
/*     */       }
/*     */       try
/*     */       {
/* 237 */         in.close();
/*     */       }
/*     */       catch (IOException e) {}
/*     */     }
/*     */     catch (XMLStreamException e)
/*     */     {
/* 227 */       ZimbraLog.soap.debug("Problem trying to determine response protocol from request XML", e);
/*     */     } finally {
/* 229 */       if (xmlReader != null) {
/*     */         try {
/* 231 */           xmlReader.close();
/*     */         }
/*     */         catch (XMLStreamException e) {}
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/* 240 */     return soapProto;
/*     */   }
/*     */   
/*     */   public Element dispatch(String path, byte[] soapMessage, Map<String, Object> context) throws CsrfTokenException {
/* 244 */     if ((soapMessage == null) || (soapMessage.length == 0)) {
/* 245 */       SoapProtocol soapProto = SoapProtocol.Soap12;
/* 246 */       return soapFaultEnv(soapProto, "SOAP exception", ServiceException.PARSE_ERROR("empty request payload", null));
/*     */     }
/*     */     
/*     */ 
/* 250 */     InputStream in = new ByteArrayInputStream(soapMessage);
/* 251 */     Element document = null;
/*     */     try {
/* 253 */       if (soapMessage[0] == 60) {
/* 254 */         document = Element.parseXML(in);
/*     */       } else {
/* 256 */         document = Element.parseJSON(in);
/*     */       }
/*     */     } catch (SoapParseException e) {
/* 259 */       SoapProtocol soapProto = SoapProtocol.SoapJS;
/* 260 */       logUnparsableRequest(context, soapMessage, e.getMessage());
/* 261 */       return soapFaultEnv(soapProto, "SOAP exception", ServiceException.PARSE_ERROR(e.getMessage(), e));
/*     */     } catch (XmlParseException e) {
/* 263 */       logUnparsableRequest(context, soapMessage, e.getMessage());
/* 264 */       SoapProtocol soapProto = chooseFaultProtocolFromBadXml(new ByteArrayInputStream(soapMessage));
/* 265 */       return soapFaultEnv(soapProto, "SOAP exception", e);
/*     */     }
/* 267 */     Element resp = dispatch(path, document, context);
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 280 */     logRequest(context, document);
/*     */     
/* 282 */     return resp;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private Element dispatch(String path, Element envelope, Map<String, Object> context)
/*     */   {
/* 297 */     SoapProtocol soapProto = SoapProtocol.determineProtocol(envelope);
/* 298 */     if (soapProto == null)
/*     */     {
/* 300 */       soapProto = SoapProtocol.Soap12;
/* 301 */       return soapFaultEnv(soapProto, "SOAP exception", ServiceException.INVALID_REQUEST("unable to determine SOAP version", null));
/*     */     }
/*     */     
/*     */ 
/* 305 */     Element doc = soapProto.getBodyElement(envelope);
/* 306 */     if (doc == null) {
/* 307 */       return soapFaultEnv(soapProto, "SOAP exception", ServiceException.INVALID_REQUEST("No SOAP body", null));
/*     */     }
/*     */     
/* 310 */     ServletRequest servReq = (ServletRequest)context.get("servlet.request");
/*     */     
/*     */ 
/*     */ 
/*     */ 
/* 315 */     DocumentHandler handler = this.dispatcher.getHandler(doc);
/* 316 */     ZimbraSoapContext zsc = null;
/* 317 */     Element ectxt = soapProto.getHeader(envelope, HeaderConstants.CONTEXT);
/*     */     try {
/* 319 */       zsc = new ZimbraSoapContext(ectxt, doc.getQName(), handler, context, soapProto);
/*     */     } catch (ServiceException e) {
/* 321 */       return soapFaultEnv(soapProto, "unable to construct SOAP context", e);
/*     */     }
/* 323 */     boolean doCsrfCheck = false;
/* 324 */     if (servReq.getAttribute("CsrfTokenCheck") != null) {
/* 325 */       doCsrfCheck = ((Boolean)servReq.getAttribute("CsrfTokenCheck")).booleanValue();
/* 326 */     } else if ((zsc.getAuthToken() != null) && (zsc.getAuthToken().isCsrfTokenEnabled())) {
/* 327 */       doCsrfCheck = true;
/*     */     }
/*     */     
/* 330 */     if (handler == null)
/*     */     {
/*     */ 
/* 333 */       if (!doc.getName().equals("BatchRequest")) {
/* 334 */         doCsrfCheck = false;
/*     */       } else {
/* 336 */         LOG.info("Only BatchRequest does not have a handler mapped to it. Request: %s, does not have a handler, log for future handling.", new Object[] { path });
/*     */       }
/*     */       
/*     */ 
/*     */     }
/* 341 */     else if (doc.getName().equals("AuthRequest"))
/*     */     {
/* 343 */       doCsrfCheck = false;
/*     */     } else {
/* 345 */       doCsrfCheck = (doCsrfCheck) && (handler.needsAuth(context));
/*     */     }
/*     */     
/* 348 */     if (doCsrfCheck) {
/*     */       try {
/* 350 */         HttpServletRequest httpReq = (HttpServletRequest)servReq;
/*     */         
/* 352 */         String csrfToken = httpReq.getHeader("X-Zimbra-Csrf-Token");
/* 353 */         if (StringUtil.isNullOrEmpty(csrfToken)) {
/* 354 */           Element contextElmt = soapProto.getHeader(envelope).getElement("context");
/* 355 */           csrfToken = contextElmt.getAttribute("csrfToken");
/*     */         }
/* 357 */         AuthToken authToken = zsc.getAuthToken();
/* 358 */         if (!CsrfUtil.isValidCsrfToken(csrfToken, authToken)) {
/* 359 */           LOG.debug("CSRF token validation failed for account. " + authToken + ", Auth token is CSRF enabled: " + authToken.isCsrfTokenEnabled() + "CSRF token is: " + csrfToken);
/*     */           
/*     */ 
/* 362 */           return soapFaultEnv(soapProto, "cannot dispatch request", ServiceException.AUTH_REQUIRED());
/*     */         }
/*     */       }
/*     */       catch (ServiceException e)
/*     */       {
/* 367 */         LOG.debug("Error during CSRF validation.", e);
/* 368 */         return soapFaultEnv(soapProto, "cannot dispatch request", ServiceException.AUTH_REQUIRED());
/*     */       }
/*     */     }
/*     */     
/* 372 */     SoapProtocol responseProto = zsc.getResponseProtocol();
/*     */     
/* 374 */     String rid = zsc.getRequestedAccountId();
/* 375 */     String proxyAuthToken = null;
/* 376 */     if (rid != null) {
/* 377 */       Provisioning prov = Provisioning.getInstance();
/* 378 */       AccountUtil.addAccountToLogContext(prov, rid, "name", "id", zsc.getAuthToken());
/* 379 */       String aid = zsc.getAuthtokenAccountId();
/* 380 */       if ((aid != null) && (!rid.equals(aid))) {
/* 381 */         AccountUtil.addAccountToLogContext(prov, aid, "aname", "aid", zsc.getAuthToken());
/* 382 */       } else if ((zsc.getAuthToken() != null) && (zsc.getAuthToken().getAdminAccountId() != null)) {
/* 383 */         AccountUtil.addAccountToLogContext(prov, zsc.getAuthToken().getAdminAccountId(), "aname", "aid", zsc.getAuthToken());
/*     */       }
/*     */       try
/*     */       {
/* 387 */         Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(rid, false);
/* 388 */         if (mbox != null) {
/* 389 */           ZimbraLog.addMboxToContext(mbox.getId());
/*     */         }
/*     */       }
/*     */       catch (ServiceException ignore) {}
/*     */       try
/*     */       {
/* 395 */         AuthToken at = zsc.getAuthToken();
/* 396 */         if (at != null) {
/* 397 */           proxyAuthToken = prov.getProxyAuthToken(rid, context);
/* 398 */           at.setProxyAuthToken(proxyAuthToken);
/*     */         }
/*     */       } catch (ServiceException e) {
/* 401 */         LOG.warn("failed to set proxy auth token: %s", new Object[] { e.getMessage() });
/*     */       }
/*     */     }
/*     */     
/* 405 */     if (zsc.getUserAgent() != null) {
/* 406 */       ZimbraLog.addUserAgentToContext(zsc.getUserAgent());
/*     */     }
/* 408 */     if (zsc.getVia() != null) {
/* 409 */       ZimbraLog.addViaToContext(zsc.getVia());
/*     */     }
/* 411 */     if (zsc.getSoapRequestId() != null) {
/* 412 */       ZimbraLog.addSoapIdToContext(zsc.getSoapRequestId());
/*     */     }
/*     */     
/* 415 */     logRequest(context, envelope);
/*     */     
/* 417 */     context.put("zimbra.context", zsc);
/* 418 */     context.put("zimbra.engine", this);
/*     */     
/* 420 */     HttpServletRequest servletRequest = (HttpServletRequest)context.get("servlet.request");
/* 421 */     boolean isResumed = !ContinuationSupport.getContinuation(servletRequest).isInitial();
/*     */     
/* 423 */     Element responseBody = null;
/* 424 */     if (!zsc.isProxyRequest())
/*     */     {
/* 426 */       acknowledgeNotifications(zsc);
/*     */       boolean contOnError;
/* 428 */       if (doc.getQName().equals(ZimbraNamespace.E_BATCH_REQUEST)) {
/* 429 */         contOnError = doc.getAttribute("onerror", "continue").equals("continue");
/* 430 */         responseBody = zsc.createElement(ZimbraNamespace.E_BATCH_RESPONSE);
/* 431 */         if (!isResumed) {
/* 432 */           ZimbraLog.soap.info(doc.getName());
/*     */         }
/* 434 */         for (Element req : doc.listElements()) {
/* 435 */           String id = req.getAttribute("requestId", null);
/* 436 */           long start = System.currentTimeMillis();
/* 437 */           Element br = dispatchRequest(this.dispatcher.getHandler(req), req, context, zsc);
/* 438 */           if (!isResumed) {
/* 439 */             ZimbraLog.soap.info("(batch) %s elapsed=%d", new Object[] { req.getName(), Long.valueOf(System.currentTimeMillis() - start) });
/*     */           }
/* 441 */           if (id != null) {
/* 442 */             br.addAttribute("requestId", id);
/*     */           }
/* 444 */           responseBody.addNonUniqueElement(br);
/* 445 */           if ((!contOnError) && (responseProto.isFault(br))) {
/*     */             break;
/*     */           }
/* 448 */           if (proxyAuthToken != null)
/*     */           {
/*     */ 
/* 451 */             zsc.getAuthToken().setProxyAuthToken(proxyAuthToken);
/*     */           }
/*     */         }
/*     */       } else {
/* 455 */         String id = doc.getAttribute("requestId", null);
/* 456 */         long start = System.currentTimeMillis();
/* 457 */         responseBody = dispatchRequest(handler, doc, context, zsc);
/* 458 */         if (!isResumed) {
/* 459 */           ZimbraLog.soap.info("%s elapsed=%d", new Object[] { doc.getName(), Long.valueOf(System.currentTimeMillis() - start) });
/*     */         }
/* 461 */         if (id != null) {
/* 462 */           responseBody.addAttribute("requestId", id);
/*     */         }
/*     */         
/*     */       }
/*     */     }
/*     */     else
/*     */     {
/*     */       try
/*     */       {
/* 471 */         doc.detach();
/* 472 */         ZimbraSoapContext zscTarget = new ZimbraSoapContext(zsc, zsc.getRequestedAccountId()).disableNotifications();
/* 473 */         long start = System.currentTimeMillis();
/* 474 */         responseBody = zsc.getProxyTarget().dispatch(doc, zscTarget);
/* 475 */         ZimbraLog.soap.info("%s proxy=%s,elapsed=%d", new Object[] { doc.getName(), zsc.getProxyTarget(), Long.valueOf(System.currentTimeMillis() - start) });
/*     */         
/* 477 */         responseBody.detach();
/*     */       } catch (SoapFaultException e) {
/* 479 */         responseBody = e.getFault() != null ? e.getFault().detach() : responseProto.soapFault(e);
/* 480 */         LOG.debug("proxy handler exception", e);
/*     */       } catch (ServiceException e) {
/* 482 */         responseBody = responseProto.soapFault(e);
/* 483 */         LOG.info("proxy handler exception", e);
/*     */       } catch (Throwable e) {
/* 485 */         responseBody = responseProto.soapFault(ServiceException.FAILURE(e.toString(), e));
/* 486 */         if ((e instanceof OutOfMemoryError)) {
/* 487 */           Zimbra.halt("proxy handler exception", e);
/*     */         }
/* 489 */         LOG.warn("proxy handler exception", e);
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 494 */     Element responseHeader = generateResponseHeader(zsc);
/*     */     
/* 496 */     return responseProto.soapEnvelope(responseBody, responseHeader);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   Element dispatchRequest(Element request, Map<String, Object> context, ZimbraSoapContext zsc)
/*     */   {
/* 503 */     SoapProtocol soapProto = zsc.getResponseProtocol();
/*     */     
/* 505 */     if (request == null) {
/* 506 */       return soapFault(soapProto, "cannot dispatch request", ServiceException.INVALID_REQUEST("no document specified", null));
/*     */     }
/*     */     
/* 509 */     DocumentHandler handler = this.dispatcher.getHandler(request);
/* 510 */     return dispatchRequest(handler, request, context, zsc);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   Element dispatchRequest(DocumentHandler handler, Element soapReqElem, Map<String, Object> context, ZimbraSoapContext zsc)
/*     */   {
/* 518 */     long startTime = System.currentTimeMillis();
/* 519 */     SoapProtocol soapProto = zsc.getResponseProtocol();
/*     */     
/* 521 */     if (soapReqElem == null) {
/* 522 */       return soapFault(soapProto, "cannot dispatch request", ServiceException.INVALID_REQUEST("no document specified", null));
/*     */     }
/*     */     
/* 525 */     if (handler == null) {
/* 526 */       return soapFault(soapProto, "cannot dispatch request", ServiceException.UNKNOWN_DOCUMENT(soapReqElem.getQualifiedName(), null));
/*     */     }
/*     */     
/* 529 */     if ((RedoLogProvider.getInstance().isSlave()) && (!handler.isReadOnly())) {
/* 530 */       return soapFault(soapProto, "cannot dispatch request", ServiceException.NON_READONLY_OPERATION_DENIED());
/*     */     }
/* 532 */     AuthToken at = zsc.getAuthToken();
/* 533 */     boolean needsAuth = handler.needsAuth(context);
/* 534 */     boolean needsAdminAuth = handler.needsAdminAuth(context);
/* 535 */     if (((needsAuth) || (needsAdminAuth)) && (at == null)) {
/* 536 */       return soapFault(soapProto, "cannot dispatch request", ServiceException.AUTH_REQUIRED());
/*     */     }
/* 538 */     Element response = null;
/* 539 */     SoapTransport.setVia(zsc.getNextVia());
/*     */     try {
/* 541 */       Provisioning prov = Provisioning.getInstance();
/* 542 */       if ((!prov.getLocalServer().getBooleanAttr("zimbraUserServicesEnabled", true)) && (!(handler instanceof AdminDocumentHandler)))
/*     */       {
/* 544 */         return soapFault(soapProto, "cannot dispatch request", ServiceException.TEMPORARILY_UNAVAILABLE());
/*     */       }
/* 546 */       if (needsAdminAuth) {
/* 547 */         AdminAccessControl aac = AdminAccessControl.getAdminAccessControl(at);
/* 548 */         if (!aac.isSufficientAdminForSoap(context, handler)) {
/* 549 */           return soapFault(soapProto, "cannot dispatch request", ServiceException.PERM_DENIED("need adequate admin token"));
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 554 */       String acctId = null;
/* 555 */       boolean isGuestAccount = true;
/* 556 */       boolean delegatedAuth = false;
/* 557 */       if (at != null) {
/* 558 */         acctId = at.getAccountId();
/* 559 */         isGuestAccount = acctId.equals("99999999-9999-9999-9999-999999999999");
/* 560 */         delegatedAuth = at.isDelegatedAuth();
/*     */       }
/*     */       
/* 563 */       if (!isGuestAccount) {
/* 564 */         if ((needsAuth) || (needsAdminAuth)) {
/*     */           try {
/* 566 */             AuthProvider.validateAuthToken(prov, at, false);
/*     */           } catch (ServiceException e) {
/* 568 */             return soapFault(soapProto, null, e);
/*     */           }
/*     */           
/*     */ 
/* 572 */           if ((zsc.isDelegatedRequest()) && (!handler.isAdminCommand())) {
/* 573 */             Account target = DocumentHandler.getRequestedAccount(zsc);
/*     */             
/*     */ 
/* 576 */             boolean inactive = (target == null) || ("maintenance".equals(target.getAccountStatus(prov)));
/*     */             
/* 578 */             if ((!inactive) && ((!at.isAdmin()) || (!AccessManager.getInstance().canAccessAccount(at, target)))) {
/* 579 */               inactive = !target.getAccountStatus(prov).equals("active");
/*     */             }
/* 581 */             if (inactive) {
/* 582 */               return soapFault(soapProto, "target account is not active", AccountServiceException.ACCOUNT_INACTIVE(target == null ? zsc.getRequestedAccountId() : target.getName()));
/*     */             }
/*     */           }
/*     */         }
/*     */         
/*     */ 
/*     */ 
/*     */ 
/* 590 */         context.put("zimbra.session", handler.getSession(zsc));
/*     */         
/*     */ 
/* 593 */         if ((needsAuth) || (needsAdminAuth)) {
/* 594 */           response = handler.proxyIfNecessary(soapReqElem, context);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 599 */       if (response == null) {
/* 600 */         if (delegatedAuth) {
/* 601 */           handler.logAuditAccess(at.getAdminAccountId(), acctId, acctId);
/*     */         }
/* 603 */         response = handler.handle(soapReqElem, context);
/* 604 */         ZimbraPerf.SOAP_TRACKER.addStat(getStatName(soapReqElem), startTime);
/* 605 */         long duration = System.currentTimeMillis() - startTime;
/* 606 */         if ((LC.zimbra_slow_logging_enabled.booleanValue()) && (duration > LC.zimbra_slow_logging_threshold.longValue()) && (!soapReqElem.getQName().getName().equals(MailConstants.SYNC_REQUEST.getName())))
/*     */         {
/* 608 */           ZimbraLog.soap.warn("Slow SOAP request (start=" + startTime + "):\n" + soapReqElem.prettyPrint(true));
/* 609 */           ZimbraLog.soap.warn("Slow SOAP response (time=" + duration + "):\n" + response.prettyPrint());
/*     */         }
/*     */       }
/*     */     } catch (SoapFaultException e) {
/* 613 */       response = e.getFault() != null ? e.getFault().detach() : soapProto.soapFault(ServiceException.FAILURE(e.toString(), e));
/* 614 */       if (!e.isSourceLocal()) {
/* 615 */         LOG.debug("handler exception", e);
/*     */       }
/*     */     } catch (AccountServiceException.AuthFailedServiceException e) {
/* 618 */       HttpServletRequest httpReq = (HttpServletRequest)context.get("servlet.request");
/*     */       
/* 620 */       httpReq.setAttribute("auth.failed", Boolean.TRUE);
/* 621 */       String clientIp = (String)context.get("request.ip");
/* 622 */       httpReq.setAttribute("request.ip", clientIp);
/*     */       
/* 624 */       response = soapProto.soapFault(e);
/*     */       
/* 626 */       if (LOG.isDebugEnabled()) {
/* 627 */         LOG.debug("handler exception: %s%s", e.getMessage(), e.getReason(", %s"), e);
/*     */       }
/*     */       else {
/* 630 */         LOG.info("handler exception: %s%s", new Object[] { e.getMessage(), e.getReason(", %s") });
/*     */       }
/*     */     } catch (ServiceException e) {
/* 633 */       response = soapProto.soapFault(e);
/* 634 */       LOG.info("handler exception", e);
/*     */     }
/*     */     catch (Throwable e)
/*     */     {
/* 638 */       if (e.getClass().getName().equals("org.eclipse.jetty.continuation.ContinuationThrowable")) {
/* 639 */         throw ((Error)e);
/*     */       }
/*     */       
/* 642 */       response = soapProto.soapFault(ServiceException.FAILURE(e.toString(), e));
/* 643 */       if ((e instanceof OutOfMemoryError)) {
/* 644 */         Zimbra.halt("handler exception", e);
/*     */       }
/* 646 */       LOG.warn("handler exception", e);
/*     */     }
/*     */     finally {
/* 649 */       SoapTransport.clearVia();
/*     */     }
/* 651 */     return response;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private String getStatName(Element request)
/*     */   {
/* 660 */     if (request == null) {
/* 661 */       return null;
/*     */     }
/* 663 */     String statName = request.getName();
/* 664 */     if (statName.endsWith("ActionRequest")) {
/* 665 */       Element action = request.getOptionalElement("action");
/* 666 */       if (action != null) {
/* 667 */         String op = action.getAttribute("op", null);
/* 668 */         if (op != null) {
/* 669 */           statName = String.format("%s.%s", new Object[] { statName, op });
/*     */         }
/*     */       }
/*     */     }
/* 673 */     return statName;
/*     */   }
/*     */   
/*     */   public DocumentDispatcher getDocumentDispatcher() {
/* 677 */     return this.dispatcher;
/*     */   }
/*     */   
/*     */   private void acknowledgeNotifications(ZimbraSoapContext zsc) {
/* 681 */     ZimbraSoapContext.SessionInfo sinfo = zsc.getSessionInfo();
/* 682 */     if (sinfo != null) {
/* 683 */       Session session = SessionCache.lookup(sinfo.sessionId, zsc.getAuthtokenAccountId());
/*     */       
/* 685 */       if ((session instanceof SoapSession)) {
/* 686 */         ((SoapSession)session).acknowledgeNotifications(sinfo.sequence);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private Element generateResponseHeader(ZimbraSoapContext zsc)
/*     */   {
/* 702 */     String authAccountId = zsc.getAuthtokenAccountId();
/* 703 */     String requestedAccountId = zsc.getRequestedAccountId();
/*     */     
/* 705 */     Element ctxt = zsc.createElement(HeaderConstants.CONTEXT);
/* 706 */     boolean requiresChangeHeader = requestedAccountId != null;
/*     */     try {
/* 708 */       ZimbraSoapContext.SessionInfo sinfo = zsc.getSessionInfo();
/* 709 */       Session session = sinfo == null ? null : SessionCache.lookup(sinfo.sessionId, authAccountId);
/* 710 */       if (session != null)
/*     */       {
/* 712 */         ZimbraSoapContext.encodeSession(ctxt, session.getSessionId(), session.getSessionType());
/*     */         
/* 714 */         if ((session instanceof SoapSession)) {
/* 715 */           SoapSession soap = (SoapSession)session;
/* 716 */           if (session.getTargetAccountId().equals(requestedAccountId)) {
/* 717 */             requiresChangeHeader = false;
/*     */           }
/*     */           
/* 720 */           if ((sinfo.created) || (soap.requiresRefresh(sinfo.sequence))) {
/* 721 */             ZimbraLog.session.debug("returning refresh block; reason=%s", new Object[] { sinfo.created ? "new session" : "sequence-based" });
/*     */             
/* 723 */             soap.putRefresh(ctxt, zsc);
/*     */           }
/*     */           
/* 726 */           soap.putNotifications(ctxt, zsc, sinfo.sequence);
/*     */           
/* 728 */           SoapContextExtension.addExtensionHeaders(ctxt, zsc, soap);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/*     */ 
/*     */ 
/* 735 */       if (requiresChangeHeader) {
/*     */         try {
/* 737 */           String explicitAcct = requestedAccountId.equals(authAccountId) ? null : requestedAccountId;
/*     */           
/*     */ 
/* 740 */           Mailbox mbox = DocumentHandler.getRequestedMailbox(zsc, false);
/* 741 */           if (mbox != null) {
/* 742 */             ctxt.addUniqueElement("change").addAttribute("token", mbox.getLastChangeID()).addAttribute("acct", explicitAcct);
/*     */           }
/*     */         }
/*     */         catch (ServiceException e) {}
/*     */       }
/*     */       
/*     */ 
/*     */ 
/* 750 */       return ctxt;
/*     */     } catch (ServiceException e) {
/* 752 */       ZimbraLog.session.info("ServiceException while putting soap session refresh data", e); }
/* 753 */     return null;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/soap/SoapEngine.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */